package com.bitsfromspace.ubertorrent.tracker;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * TrackerTier hold a single tier of trackers. Method {@link #getNextAnnounceTracker()} returns
 * the tracker that should be announced next in this tier. The selection of the next tracker to
 * announce is based on the following order:
 * 
 *
	 * <ul>
	 * <li>If one tracker was successfully announced before, that will be the next to announce.</li>
	 * <li>If more that one tracker was successfully announced before <b>or</b> none of the trackers
	 * was successfully announced, the tracker with the lowest value for {@link Tracker#getNextAnnounceDate()} is returned. </li>
	 * <li>If the values for the next announce data are equal, which will be the case for the first announce, 
	 * the Tracker is randomly selected </li>
	 * </ul>
	 *     
	 
 * @author: chris.oudeman
 * @since: Jan 5, 2011
 */
public class TrackerTier {

	private final List<Tracker> tier;


	/**
	 * Creates a new {@link TrackerTier} with the specified trackers.
	 */
	public TrackerTier(List<Tracker> trackers) {

		this.tier = trackers;
	}

	/**
	 * Returns a copy of all trackers in this tier.
	 */
	public List<Tracker> getTrackers() {

		return new ArrayList<Tracker>(tier);
	}

	/**
	 * Returns the next tracker that should be announced, according to the
	 * multitracker metadata extension specification.<br/>
	 * The next tracker to announce WITHIN a tier is defined as:<br/>
	 * <ul>
	 * <li>If one tracker was successfully announced before, that will be the next to announce.</li>
	 * <li>If more that one tracker was successfully announced before <b>or</b> none of the trackers
	 * was successfully announced, the tracker with the lowest value for {@link Tracker#getNextAnnounceDate()} is returned. </li>
	 * <li>If the values for the next announce data are equal, which will be the case for the first announce, 
	 * the Tracker is randomly selected </li>
	 * </ul>
	 * Returns null when this tier is empty;
	 *     
	 */
	public Tracker getNextAnnounceTracker() {

		if (tier.isEmpty()) {
			return null;
		}
		Collections.sort(tier, TIER_ORDER_COMPARATOR);
		return tier.get(0);
	}

	private static Comparator<Tracker> TIER_ORDER_COMPARATOR =
			new Comparator<Tracker>() {

				@Override
				public int compare(Tracker t1, Tracker t2) {

					// 1. trackers that are successfull are more important
					if (t1.isWasAnnounceSuccessfull()
							&& !t2.isWasAnnounceSuccessfull()) {
						return -1;
					}
					if (!t1.isWasAnnounceSuccessfull()
							&& t2.isWasAnnounceSuccessfull()) {
						return 1;
					}

					//2. If trackers have same state, order by nextSuccessfullScrape date descending...

					return Trackers.TRACKERS_COMPARATOR.compare(t1, t2);
				}
			};
}


